package es.uca.plii.warrenl0;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * Implementación concreta de un nodo tipo estructura, va a representar a
 * cualquier nodo que no sea una variable
 * @author Rafael Sánchez, Alfonso Sendra
 */
public class NodoEstructura extends NodoImpl {

    String nombre;
    List<Nodo> contenido = new ArrayList<Nodo>();

    /**
     * Devuelve el tipo de nodo concreto que se está implementando
     * @return Nodo.NODOESTRUCTURA
     */
    public int getTipo() {
        return Nodo.NODOESTRUCTURA;
    }

    /**
     * Constructor de la clase. Construye un nodo estructura a partir de
     * el nombre de un functor
     * @param nombre el nombre del functor
     */
    public NodoEstructura(String nombre) {
        this.nombre = nombre;
    }

    /**
     * Añade un nodo hijo
     * @param nodo el nodo a añadir
     */
    public void AnadirNodo(Nodo nodo) {
        contenido.add(nodo);
    }

    /**
     * Devuelve el número de nodos hijos que tiene
     * @return el número de nodos hijos
     */
    public int getAridad() {
        return contenido.size();
    }


    public void numerarProfundidades(int profundidad, ExtractorProfundidades ep) {
        profundidad++;
        ep.anadirNodoAlMapa(Integer.valueOf(profundidad), this);
        for (Nodo hijo : contenido) {
            hijo.numerarProfundidades(profundidad,ep);
        }
    }



    public String flattenedForm()
    {
        StringBuilder f = new StringBuilder();
        f.append(nombre);
        f.append("(");
        int tamano = this.contenido.size();
        int contador = 0;
        Nodo c = null;
        while(contador < tamano)
        {
            f.append("X");
            c = this.contenido.get(contador);
            f.append(c.getNumero());
            contador++;
            if(contador<tamano)
                f.append(",");
        }
        f.append(")");
        return f.toString();
    }

    /**
     * Devuelve la representación tokenizada del nodo
     * @return la representación tokenizada
     */
    public String tokenizedForm()
    {
        StringBuilder f = new StringBuilder();
        f.append(nombre);
        f.append("/");
        int tamano = this.contenido.size();
        f.append(tamano);
        if(tamano>0)
            f.append(",");
        int contador = 0;
        Nodo c = null;
        while(contador < tamano)
        {
            f.append("X");
            c = this.contenido.get(contador);
            f.append(c.getNumero());
            contador++;
            if(contador<tamano)
                f.append(",");
        }
        return f.toString();
    }

    /**
     * Devuelve la representación en instrucciones M0 del nodo
     * @return la representación en instrucciones M0
     */
    public CompInstruccion instruction() {
        CompInstruccion compInstruccion = new CompInstruccion();
        compInstruccion.argumentos = new ArrayList<Integer>();

        StringBuilder f = new StringBuilder();
        f.append(nombre);
        f.append("/");
        int tamano = this.contenido.size();
        f.append(tamano);
        compInstruccion.cabecera = f.toString();

        int contador = 0;
        Nodo c = null;
        while(contador < tamano)
        {
            c = this.contenido.get(contador);
            compInstruccion.argumentos.add(c.getNumero());
            contador++;
        }

        return compInstruccion;

    }

     public void obtenerFlattenedForms(Map<Integer, String> flt) {
       for(Nodo n : this.contenido)
           n.obtenerFlattenedForms(flt);
       flt.put(getNumero(), flattenedForm());
    }

     public void obtenerTokenizedForms(Map<Integer, String> flt) {
       for(Nodo n : this.contenido)
           n.obtenerTokenizedForms(flt);
       flt.put(getNumero(), tokenizedForm());
    }

     public void obtenerInstructions(Map<Integer, CompInstruccion> flt) {
       for(Nodo n : this.contenido)
           n.obtenerInstructions(flt);
       flt.put(getNumero(), instruction());
     }


}
